// James Fancy, May 2009

// Object alCommon
var alCommon = {
    $MARK: "AUTOLOGIN-VER1.0-JAMESFANCY-HAPPY.JAMESFANCY.CN",
    getMark: function() {
        return alCoder.base64.encode(this.$MARK);
    },
    verifyMark: function(base64Code) {
        if (typeof(base64Code) != "string") {
            return false;
        }
        var mark = alCoder.base64.decode(base64Code);
        return (mark.match(/AUTOLOGIN-VER[\d\.]+?-JAMESFANCY-HAPPY.JAMESFANCY.CN/) != null);
    }
};

// class AlUserSetting
function AlUserSetting(map, site) {
    this.$data = {};
    this.$summary = null;

    this.set = function(map, site) {
        this.$init(map, site);
        return this;
    }

    this.$init = function(map, site) {
        if (typeof(map) != "object") {
            return;
        }

        this.$data = {};
        for (var key in map) {
            if (typeof(map[key]) == "function") {
                continue;
            }
            this.$data[key] = map[key];
        }

        if (typeof(site) == "string") {
            this.$data.$_ = site;
        }

        this.$getSummary();
    }

    this.toString = function() {
        var buffer = "$_=" + this.$data.$_;
        for (var key in this.$data) {
            if (key == "$_") {
                continue;
            }
            buffer += "\n" + key + "=" + this.$data[key];
        }
        return buffer;
    }

    this.fromString = function(buffer) {
        var lines = buffer.split(/\n/);
        var setting = {};
        for (var i = 0; i < lines.length; i++) {
            var pair = lines[i].split(/=/, 2);
            if (pair.length != 2) {
                continue;
            }
            setting[pair[0]] = pair[1];
        }
        this.$init(setting);

        return this;
    }

    this.$getSummary = function() {
        this.$summary = alCoder.md5.HEX(this.toString());
    }

    this.isMatchSummary = function(summary) {
        return this.$summary === summary;
    }

    this.summary = function() {
        return this.$summary;
    }

    this.data = function() {
        return this.$data;
    }

    this.$init(map, site);
}

// class AlUser
function AlUser(name, img, base64code) {
    this.$name = name;
    this.$img = img;
    if (typeof(base64code) == "string") {
        this.$des = alCoder.base64.decode(base64code);
    }
    this.$password;
    this.$settingPath;
    this.$settings = [];

    this.init = function(name, img, password, path) {
        this.$name = name;
        this.$img = img;
        this.$password = password;
        this.$settingPath = path;
        return this;
    };

    this.name = function(n) {
        if (typeof(n) != "undefined") {
            this.$name = n;
        }
        return this.$name;
    };

    this.img = function(img) {
        if (typeof(img) != "undefined") {
            this.$img = img;
        }
        return this.$img;
    };

    this.password = function(pass) {
        if (typeof(pass) != "undefined") {
            this.$password = pass;
        }
        return this.$password;
    };

    this.settingPath = function(path) {
        if (typeof(path) != "undefined") {
            this.$settingPath = path;
        }

        if (typeof(this.$settingPath) != "string") {
            if (!this.$decrypt()) {
                return null;
            }
        }
        return this.$settingPath;
    };

    this.is = function(name) {
        if (typeof(name) != "string" || typeof(this.$name) != "string") {
            return false;
        } else {
            return name.toLowerCase() == this.$name.toLowerCase();
        }
    };

    this.toString = function() {
        return [
            this.$name || "none",
            this.$img || "def",
            //alCoder.hex.encode(this.$des || this.$encrypt())
            alCoder.base64.encode(this.$des || this.$encrypt())
        ].join(":");
    };

    this.login = function(password) {
        this.password(password);
        return this.$decrypt();
    };

    this.$encrypt = function() {
        var password = this.$password || "password";
        var path = this.$settingPath || "";
        this.$des = alCoder.des.encrypt(password, "PASS{" + password + "}" + path);
        return this.$des;
    };

    this.$decrypt = function() {
        var t = alCoder.des.decrypt(this.$password, this.$des);
        if (!t.match("^PASS\{" + this.$password + "\}")) {
            return false;
        } else {
            this.$settingPath = t.substr(this.$password.length + 6);
            return true;
        }
    };

    this.getSettings = function() {
        return this.$settings;
    };

    this.addSetting = function(obj, web) {
        if (typeof(obj) != "object") {
            return;
        }

        if (typeof(web) == "string") {
            obj[$_] = web;
        }

        this.$settings.push(obj);

        return this;
    }

    this.removeSetting = function(summary) {
        if (typeof(summary) == "object") {
            summary = summary.summary();
        }
        if (typeof(summary) == "undefined") {
            return;
        }

        for (var i = 0; i < this.$settings.length; i++) {
            if (this.$settings[i].isMatchSummary(summary)) {
                this.$settings.splice(i, 1);
                return;
            }
        }
    }

    this.loadSetting = function() {
        var reader = new AlFsoReader(this.$settingPath);
        if (!reader.isValid()) {
            return;
        }

        if (!alCommon.verifyMark(reader.readLine())) {
            reader.close();
            return;
        }

        this.$settings = [];
        for (var line = reader.readLine(); line != null; line = reader.readLine()) {
            this.$settings.push(this.$settingFromString(line));
        }

        return this;
    };

    this.$settingFromString = function(code) {
        var buffer = alCoder.des.decrypt(this.password(), alCoder.base64.decode(code));
        return new AlUserSetting().fromString(buffer);
    };

    this.saveSetting = function() {
        var writer = new AlFsoWriter(this.$settingPath);
        if (!writer.isValid()) {
            return;
        }
        writer.writeLine(alCommon.getMark());
        for (var i = 0; i < this.$settings.length; i++) {
            writer.writeLine(this.$settingToString(this.$settings[i]));
        }
        writer.close();

        return this;
    };

    this.$settingToString = function(aSetting) {
        return alCoder.base64.encode(alCoder.des.encrypt(this.password(), aSetting.toString()));
    };
}

// class AlUserInfo
function AlUserInfo(filename) {
    if (typeof(filename) != "string") {
        return;
    }
    this.$filename = filename;

    this.$users = new Array();

    this.read = function() {
        var reader = new AlFsoReader(this.$filename);
        if (!reader.isValid()) {
            return;
        }

        if (!alCommon.verifyMark(reader.readLine())) {
            reader.close();
            return;
        }

        this.$users = new Array();
        for (var line = reader.readLine(); line != null; line = reader.readLine()) {
            if (line.match(/^[ \t]*$/)) {
                continue;
            }
            var parts = line.split(/:/, 3);
            if (parts.length != 3) {
                break;
            }

            this.$users.push(new AlUser(parts[0], parts[1], parts[2]));
        }
    };

    this.save = function() {
        var writer = new AlFsoWriter(this.$filename);
        if (!writer.isValid()) {
            // TODO: output error message
            return;
        }

        writer.writeLine(alCommon.getMark());
        for (var i = 0; i < this.$users.length; i++) {
            writer.writeLine(this.$users[i].toString());
        }
        writer.close();
    };

    this.getUserList = function() {
        return this.$users;
    };

    this.getUser = function(username) {
        for (var i = 0; i < this.$users.length; i++) {
            if (this.$users[i].is(username)) {
                return this.$users[i];
            }
        }
        return null;
    };

    this.addUser = function(user) {
        if (this.getUser(user.name()) != null) {
            return false;
        }

        this.$users.push(user);
        return true;
    };

    // initialize
    this.read();
}
